#include "lcd1602.h"

/* you need edit this code, port to your project */
#ifdef __SDCC
#define RS P2_6
#define RW P2_5
#define E P2_7
#else // Keil C51
sbit RS=P2^6;  //定义数据命令选择端
sbit RW=P2^5;  //定义读写选择端
sbit E=P2^7;   //定义使能端
#endif

#define UP_ROW 0
#define LOW_ROW 1

uchar pdata empty_str[] = "                ";

static void delay_ms(uint z)  //毫秒级延时函数
{
    uint i,j;
    for(i=z;i>0;i--)
        for(j=110;j>0;j--);
}

void lcd1602_part_clear(bit row, uchar column, uchar length)
{
    lcd1602_show(row, column, empty_str + 16 - length);
}

void lcd1602_clear(void)
{
    lcd1602_write_com(0x01);
}

uchar lcd1602_read_busy()   //判断lcd1602是否处于忙的状态，即读忙
{
    uchar temp;
    RS=0;
    RW=1;
    _nop_();
    P0=0xff;     //读某IO口数据前，先将该口置为1            

    _nop_();
    E=1;
    _nop_();
    temp=P0;   //读取此时lcd1602的状态字
    _nop_();
    E=0;
    return (temp&0x80);  //如果忙

    /*状态字为temp（8位2进制数）的最高位，最高位为1表示禁止读写，为0表示允许读写，即temp&0x80得1表示忙，得0表示不忙*/
}

void lcd1602_show(bit row, uchar column, uchar * str)
{
    if(row == UP_ROW)
        lcd1602_write_com(0x80 + column);
    else if(row == LOW_ROW)
        lcd1602_write_com((uchar )0x80+0x40 + column);
    
    while(*str != '\0')
    {
        lcd1602_write_data(*str);
        str ++;
    }
}
void lcd1602_write_com(uchar com)  //写命令
{
    while(lcd1602_read_busy());  //判忙
    RS=0;   //命令
    RW=0;   //写
    _nop_();
    P0=com;   //准备发送命令
    _nop_();
    E=1;      //由时序图知，使能端为高电平时才允许数据交换
    _nop_();
    _nop_();
    E=0;      //由时序图知，使能端在完成数据交换后要拉低
    _nop_();
    _nop_();   
}

void lcd1602_write_data(uchar dat)  //写数据
{
    while(lcd1602_read_busy());   //判忙
    RS=1;   //数据
    RW=0;   //写
    _nop_();
    P0=dat;
    _nop_();
    E=1;
    _nop_();
    _nop_();
    E=0;
    _nop_();
    _nop_();   
}

void lcd1602_init()   //初始化函数
{
    delay_ms(15);
    lcd1602_write_com(0x38);   //显示模式设置
    delay_ms(5);
    lcd1602_write_com(0x38);
    delay_ms(5);
    lcd1602_write_com(0x38);
    lcd1602_write_com(0x0c);  //显示开
    lcd1602_write_com(0x01);  //显示清屏
    lcd1602_write_com(0x06);  //显示光标
}
